package org.example.order.infrastructure.repo;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.example.application.context.RequestContext;
import org.example.order.domain.*;
import org.example.order.infrastructure.dao.OrderDao;
import org.example.order.infrastructure.dao.OrderDetailDao;
import org.example.order.infrastructure.po.OrderDetailPO;
import org.example.order.infrastructure.po.OrderPO;
import org.example.order.infrastructure.repo.converter.OrderConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Repository
public class OrderRepositoryImpl implements OrderRepository {
    private final OrderDao orderDao;
    private final OrderDetailDao orderDetailDao;
    private final OrgRepository orgRepository;
    private final ProductRepository productRepository;
    private final CustomerRepository customerRepository;

    public OrderRepositoryImpl(@Autowired OrderDao orderDao, @Autowired OrderDetailDao orderDetailDao, @Autowired OrgRepository orgRepository, @Autowired ProductRepository productRepository, @Autowired CustomerRepository customerRepository) {
        this.orderDao = orderDao;
        this.orderDetailDao = orderDetailDao;
        this.orgRepository = orgRepository;
        this.productRepository = productRepository;
        this.customerRepository = customerRepository;
    }

    @Override
    public Order getOrder(String orderId) {
        return getOrderFromDB(orderId);
    }

    private Order getOrderFromDB(String orderId) {
        final String tenantId = getTenantId();
        final OrderPO orderPO = orderDao.findOrderById(orderId, tenantId);
        if (orderPO == null) {
            return null;
        }
        final Org org = getOrderOrg(orderPO);
        final Customer customer = getOrderCustomer(orderPO);
        final Order order = OrderConverter.INSTANCE.convert(orderPO, org, customer);
        List<OrderDetailPO> orderDetailPOList = orderDetailDao.findOrderDetailsByOrderId(orderId, tenantId);
        if (CollectionUtils.isNotEmpty(orderDetailPOList)) {
            final Map<String, Product> products = getOrderProducts(orderDetailPOList);
            List<OrderDetail> orderDetails = orderDetailPOList.stream().map(detailPO -> {
                Product product = null;
                if (StringUtils.isNotEmpty(detailPO.getProductId())) {
                    product = products.get(detailPO.getProductId());
                }
                return OrderConverter.INSTANCE.convert(detailPO, product);
            }).collect(Collectors.toList());
            order.setDetails(orderDetails);
        }
        return order;
    }

    private Org getOrderOrg(OrderPO orderPO) {
        if (StringUtils.isNotEmpty(orderPO.getOrgId())) {
            return orgRepository.getOrg(orderPO.getOrgId());
        }
        return null;
    }

    private Customer getOrderCustomer(OrderPO orderPO) {
        if (StringUtils.isNotEmpty(orderPO.getCustomerId())) {
            return customerRepository.getCustomer(orderPO.getCustomerId());
        }
        return null;
    }

    private Map<String, Product> getOrderProducts(List<OrderDetailPO> orderDetailPOList) {
        List<String> productIds = orderDetailPOList.stream().map(OrderDetailPO::getProductId).collect(Collectors.toList());
        List<Product> products = productRepository.getProducts(productIds);
        if (CollectionUtils.isEmpty(products)) {
            return new HashMap<>();
        } else {
            return products.stream().collect(Collectors.toMap(Product::getId, Function.identity()));
        }
    }

    private String getTenantId() {
        return RequestContext.getInstance().getTenantId();
    }
}
